
#include <sys/types.h>
#include <unistd.h>

#include <sstream>
using namespace std;

#include "LogFile.hpp"
#include "LogCommon.hpp"

namespace tulun
{
    // LogFile::
    // const std::string basename_;
    // const size_t rollSize_; // 10M
    // const int flushInterval_;
    // const int checkEventN_;
    // int count_;

    // time_t startOfPeriod_;
    //  time_t lastRoll_;
    //  time_t lastFlush_;
    //  static const int kRollPerSeconds_ = 60 * 60 * 24;   //一天的秒数

    // std::unique_ptr<tulun::AppendFile> file_;
    // std::unique_ptr<std::mutex> mutex_;

    const std::string hostname()
    {
        char buff[SMALL_BUFF_SIZE] = {};
        if (!::gethostname(buff, SMALL_BUFF_SIZE))
        {
            return std::string(buff);
        }
        else
        {
            return std::string("unknownhost");
        }
    }
    pid_t pid()
    {
        return ::getpid();
    }

    std::string LogFile::getLogFileName(const std::string &basename, const tulun::Timestamp &now)
    {
        std::string filename;
        filename.reserve(basename.size() + SMALL_BUFF_SIZE);
        filename = basename;
        filename += ".";
        filename += now.toFormattedFile();
        filename += ".";
        filename += hostname();
        std::stringstream ss;
        ss << "." << pid() << ".log";
        filename += ss.str();
        return filename;
    }
    void LogFile::append_unlocked(const char *msg, const size_t len)
    {
        file_->append(msg, len);
        if (file_->getWriteBytes() > rollSize_)
        {
            rollFile();
        }
        else
        {
            count_ += 1;
            if (count_ > checkEventN_)
            {
                count_ = 0;
                time_t now = time(nullptr);
                time_t thisPeriod = (now / kRollPerSeconds_) * kRollPerSeconds_;
                if (thisPeriod != startOfPeriod_)
                {
                    rollFile();
                }
                else if (now - lastFlush_ > flushInterval_)
                {
                    lastFlush_ = now;
                    file_->flush();
                }
            }
        }
    }

    LogFile::LogFile(const std::string &basename,
                     size_t rollSize,
                     int flushInterval,
                     int checkEventN,
                     bool threadSafe)
        : basename_(basename),
          rollSize_(rollSize),
          flushInterval_(flushInterval),
          checkEventN_(checkEventN),
          count_(0),
          //   mutex_(threadSafe ? new std::mutex{} : nullptr),
          startOfPeriod_(0),
          lastFlush_(0),
          lastRoll_(0)
    {
        if (threadSafe)
        {
            mutex_.reset(new std::mutex());
        }
        rollFile();
    }
    LogFile::~LogFile()
    {
    }
    void LogFile::append(const std::string &msg)
    {
        append(msg.c_str(), msg.size());
    }
    void LogFile::append(const char *msg, const size_t len)
    {
        if (mutex_)
        {
            std::unique_lock<std::mutex> lock(*mutex_);
            append_unlocked(msg, len);
        }
        else
        {
            append_unlocked(msg, len);
        }
    }
    void LogFile::flush()
    {
        file_->flush();
    }
    bool LogFile::rollFile()
    {
        tulun::Timestamp now(tulun::Timestamp::Now());
        std::string filename = getLogFileName(basename_, now);
        time_t start = (now.getsecond() / kRollPerSeconds_) * kRollPerSeconds_;
        if (now.getsecond() > lastRoll_)
        {
            lastRoll_ = now.getsecond();
            lastFlush_ = now.getsecond();
            startOfPeriod_ = start;
            file_.reset(new tulun::AppendFile(filename));
            return true;
        }
        return false;
    }

} // namespace tulun